package utils

import (
	"VideoManageSystem/internal/model"
	"errors"
	"fmt"
	"time"

	"github.com/golang-jwt/jwt/v4"
	"go.uber.org/zap"
)

// 定义密钥和过期时间
// 这个密钥生成逻辑后面要改。。。。。。。。！！！！！！
var jwtSecret = []byte("qwertyuiopasdfghjklzxcvbnm") // 预定义的密钥
var tokenExpireDuration = time.Hour * 24             // Token 有效期为 24 小时

// Claims 定义 JWT 的载荷
type Claims struct {
	ID        string `json:"id"`  // 自定义字段：用户唯一标识
	ExpiresAt int64  `json:"exp"` // 标准字段：过期时间
	Issuer    string `json:"iss"` // 标准字段：签发者
}

// Valid 实现 jwt.Claims 接口
func (c *Claims) Valid() error {
	// 检查 Token 是否已过期
	if time.Now().Unix() > c.ExpiresAt {
		return errors.New("token is expired")
	}
	// 可以添加其他验证逻辑，例如签发者是否合法
	if c.Issuer != "VideoManageSystem" {
		return errors.New("invalid issuer")
	}
	return nil
}

// GenerateToken 生成 JSON Web Token
func GenerateToken(user *model.User) (string, error) {
	// Claims 是一个自定义结构体
	// 在这里，我们添加了一个字段 ID，用于存储用户的唯一标识
	claims := Claims{
		ID:        user.ID,
		ExpiresAt: time.Now().Add(tokenExpireDuration).Unix(), // 设置过期时间
		Issuer:    "VideoManageSystem",                        // 设置 Token 的签发者（Issuer）
	}

	// 使用 jwt.SigningMethodHS256（HMAC SHA-256 签名算法）创建一个新的 JWT Token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, &claims)

	// 使用 jwtSecret（预定义的密钥）对 Token 进行签名，并生成最终的 JWT 字符串。
	// 返回值是一个完整的 JWT Token（由 Header、Payload 和 Signature 组成）
	signedToken, err := token.SignedString(jwtSecret)
	if err != nil {
		zap.L().Error("无法生成用户Token", zap.Error(err))
		return "", err
	}
	return signedToken, nil
}

// ParseToken 解析 JWT Token
func ParseToken(tokenString string) (*Claims, error) {
	// 定义一个空的 Claims 实例
	var claims Claims

	// 解析 Token
	token, err := jwt.ParseWithClaims(tokenString, &claims, func(token *jwt.Token) (interface{}, error) {
		// 检查签名方法是否为 HMAC
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return jwtSecret, nil
	})

	if err != nil {
		// 捕获 Token 过期错误
		var ve *jwt.ValidationError
		if errors.As(err, &ve) {
			if ve.Errors&jwt.ValidationErrorExpired != 0 {
				return nil, err
			}
		}
		zap.L().Error("无法解析用户Token", zap.Error(err))
		return nil, err
	}

	// 验证 Token 是否有效
	if token.Valid {
		return &claims, nil
	}

	return nil, err
}
